#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <cstring>
#include "Threadpool.hpp"
#include "Task.hpp"
#include "log.hpp"
#define NUM 1024
using namespace std;

static const uint16_t gport = 8080;
static const int gbacklog = 5; // 这里暂时不需要了解
enum
{
    USAGE_ERROR = 1,
    SOCK_ERROR,
    BIND_ERROR,
    LISTEN_ERROR
};
class tcpserver;

struct serverData
{
    serverData(tcpserver *ts, int sock)
        : _ts(ts), _sock(sock)
    {
    }
    tcpserver *_ts;
    int _sock;
};

class tcpserver
{
public:
    tcpserver(const uint16_t &port = gport)
        : _port(port), _listenfd(-1)
    {
    }
    void initServer()
    {
        // 1.创建tcp套接字
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenfd < 0)
        {
            // 错误信息放到日志中
            logmessage(FATAL, "socket create fail");
            exit(SOCK_ERROR);
        }
        logmessage(NORMAL, "socket create success");
        // 绑定bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        if (bind(_listenfd, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            // 错误信息放到日志中
            logmessage(FATAL, "bind fail");
            exit(BIND_ERROR);
        }
        logmessage(NORMAL, "bind success");
        // 监听
        if (listen(_listenfd, gbacklog) != 0)
        {
            // 错误信息放到日志中
            logmessage(FATAL, "listen fail");
            exit(LISTEN_ERROR);
        }
        logmessage(NORMAL, "listen success");
    }
    void start()
    {
        // 线程池初始化
        Threadpool<Task>::GetInstance()->run();
        logmessage(NORMAL, "getInstance success");
        // signal(SIGCHLD,SIG_IGN); // 让父进程不需要等待子进程。
        for (;;)
        {
            // 连接,注意这里连接之后是创建新的文件描述符，和listenfd是不相同的！
            struct sockaddr_in client; // 这里要连接的client
            socklen_t len = sizeof(client);
            int sock = accept(_listenfd, (struct sockaddr *)&client, &len);
            // 这里的创建出新的文件描述符，可以直接用于通信，这里本质草所就是文件操作
            if (sock < 0)
            {
                // 错误信息放到日志中
                logmessage(ERROR, "accept fail");
                continue; // 这里创建失败可以再次创建，不是严重的错误
            }
            logmessage(NORMAL, "accept succes");
            cout << "create sock : " << sock << endl;
            // //version2 多线程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //子进程
            //     //关闭父进程的listenfd，因为子进程不需要完成监听工作
            //     close(_listenfd);
            //     //if(fork()>0) exit(0); // 这里让子进程退出，让孙子进程完成任务，完成任务后会被OS领养
            //     serviceIO(sock);
            //     close(sock);
            //     exit(0);
            // }

            // // 每次使用完都关闭，否者会导致文件描述符越用越少。
            // close(sock); // 这里父进程可以关闭，因为这里的关闭并不是真正的关闭而是引用计数--。
            // //等待子进程，这里可以通过设置信号解决，但是也可以通过孤儿进程被OS领养来解决
            // // int n = waitpid(id,nullptr,0);
            // // if(n > 0)
            // // {
            // //     cout<<"wait success"<<endl;
            // // }

            // //version3多线程
            // pthread_t pid;
            // serverData* sd = new serverData(this,sock);
            // pthread_create(&pid,nullptr,start_routine,sd);

            // version4线程池
            // 获取单例
            Threadpool<Task>::GetInstance()->push(Task(sock, serviceIO));
        }
    }
    // static void* start_routine(void* args)
    // {
    //     //线程分离
    //     pthread_detach(pthread_self());
    //     serverData* sd = static_cast<serverData*>(args);
    //     sd->_ts->serviceIO(sd->_sock);
    //     close(sd->_sock);
    //     delete sd;
    //     return nullptr;
    // }
    ~tcpserver()
    {
    }

private:
    uint16_t _port; // 端口号
    int _listenfd;  // 监听套接字
};